#include "protreewidget.h"

#include <QDir>
#include <QDebug>
#include <QHeaderView>
#include <QVector>
#include "protreeitem.h"
#include "const.h"
#include <QAction>
#include <QGuiApplication>
#include <QMenu>
#include <QFileDialog>
#include <QTreeWidgetItem>
#include <QString>
#include <QTextCodec>
#include<QtMultimedia/QMediaPlayer>
#include<QtMultimedia/QMediaPlaylist>

#include "removeprodialog.h"

#include "./SlideShowDlg/slideshowdlg.h"

ProTreeWidget::ProTreeWidget(QWidget *parent)
    : QTreeWidget(parent), _right_btn_item(nullptr), _active_item(nullptr)
    , _selected_item(nullptr), _dialog_progress(nullptr), _thread_create_pro(nullptr), _thread_open_pro(nullptr)

{
    // QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
    qRegisterMetaType<QVector<int>>("QVector<int>");

    // 隐藏表头，不然会有多余的数字哦
    this->header()->hide();

    connect(this, &ProTreeWidget::itemPressed, this, &ProTreeWidget::SlotItemPressed);
    // 双击左侧目录树实现图片切换
    connect(this, &ProTreeWidget::itemDoubleClicked, this, &ProTreeWidget::SlotDoubleClickItem);

    _action_import = new QAction(QIcon(":/icon/import.png"), tr("导入文件"), this);
    _action_setstart = new QAction(QIcon(":/icon/core.png"), tr("设置活动项目"), this);
    _action_closepro = new QAction(QIcon(":/icon/close.png"), tr("关闭项目"), this);
    _action_slideshow = new QAction(QIcon(":/icon/slideshow.png"), tr("轮播图play"), this);
    connect(_action_import, &QAction::triggered, this, &ProTreeWidget::SlotImport);
    connect(_action_setstart, &QAction::triggered, this, &ProTreeWidget::SlotSetActive);
    connect(_action_closepro, &QAction::triggered, this, &ProTreeWidget::SlotClosePro);    
    connect(_action_slideshow, &QAction::triggered, this, &ProTreeWidget::SlotSlideShow); // 轮播图

    // 设置音乐
    _player = new QMediaPlayer(this);
    _playlist = new QMediaPlaylist(this);
    _playlist->setPlaybackMode(QMediaPlaylist::Loop); // 设置循环模式
    _player->setPlaylist(_playlist); // 获取将播放列表要播放的文件
}


//// 创建项目
void ProTreeWidget::AddProToTree(const QString &name, const QString &path)
{
    qDebug() << "ProTreeWidget::AddProToTree name is " << name << " path is " << path << Qt::endl;

    QDir dir(path);
    QString file_path = dir.absoluteFilePath(name);
    // 后面直接使用一个匿名对象来判断是否已经存在 file_path 这个目录(上一步的 ProSetPage 页面判断，是判断是否存在 path，并没有加上 name)
    // if(_set_path.find(file_path) != _set_path.end() && QDir(file_path).exists() == true){
    if(_set_path.find(file_path) != _set_path.end()){
        qDebug() << "file has load" << Qt::endl;

        return;
    }

    QDir pro_dir(file_path);
    if(pro_dir.exists() == false){ // 不存在的话
        bool enable = pro_dir.mkpath(file_path);
        if(enable == false) return; // 创建不成功就 return 掉
    }

    // qDebug() << "......" << Qt::endl; // debug
    _set_path.insert(file_path); // 创建成功了就创建成功的 file_path 保存到 _set_path 中
    auto* item = new ProTreeItem(this, name, file_path, TreeItemPro);
    item->setData(0, Qt::DisplayRole, name);
    item->setData(0, Qt::DecorationRole, QIcon(":/icon/dir.png"));
    item->setData(0, Qt::ToolTipRole, file_path);

    // this->setStyle("QTreeView::branch:closed:has-children {image: url(:/icon/right.png);} QTreeView::branch:open:has-children {image: url(:/icon/down.png);}");

    this->addTopLevelItem(item);

    // debug --> 构造函数没有写
    // int itemtype = item->type();
    // if(itemtype == TreeItemPro){ // 点击了条目
    //     qDebug() << "itemtype == TreeItemPro" << Qt::endl;
    // }
}
// 点击了 ProTreeWidget 中的
void ProTreeWidget::SlotItemPressed(QTreeWidgetItem *pressedItem, int column)
{
    // qDebug() << "ProTreeWidget is pressed" << Qt::endl; // 可以看到，点击了 ProTreeWidget 中的文件夹的时候是会触发这个函数的
    qDebug() << "ProTreeWidget::SlotItemPressed" << Qt::endl;

    //
    if(QGuiApplication::mouseButtons() == Qt::RightButton){
        QMenu menu(this);
        qDebug() << "menu addr is " << &menu << Qt::endl;
        int itemtype = (int)(pressedItem->type());
        if(itemtype == TreeItemPro){ // 点击了条目
            // qDebug() << "itemtype == TreeItemPro" << Qt::endl; // debug
            _right_btn_item = pressedItem;
            menu.addAction(_action_import);
            menu.addAction(_action_setstart);
            menu.addAction(_action_closepro);
            menu.addAction(_action_slideshow);
            menu.exec(QCursor::pos()); // 菜单弹出位置为鼠标点击位置
        }
    }
}
// 右键点击了条目 --> 产生一个菜单 --> 点击了菜单 _action_import --> 导入文件
void ProTreeWidget::SlotImport(){
    QFileDialog file_dialog;
    file_dialog.setFileMode(QFileDialog::Directory);
    file_dialog.setWindowTitle(tr("选择导入的文件夹"));
    QString path = "";
    // if(_right_btn_item == false){ // error
    if(!_right_btn_item){
        qDebug() << "_right_btn_item is empty" << Qt::endl;
        // path = QDir::currentPath();
        return;
    }
    // qDebug() << "_right_btn_item not empty" << Qt::endl; // debug

    path = dynamic_cast<ProTreeItem*>(_right_btn_item)->GetPath();
    file_dialog.setDirectory(path);
    file_dialog.setViewMode(QFileDialog::Detail);

    //
    QStringList fileNames;
    if(file_dialog.exec()){
        fileNames= file_dialog.selectedFiles();
    }
    if(fileNames.length() <= 0){
        return;
    }
    QString import_path = fileNames.at(0); // 其实只用到第一个文件夹就行了

    // 模态框实现导入文件的进度展示
    int file_count = 0;
    _dialog_progress = new QProgressDialog(this);

    // 启动加载导入图片的线程（注意：线程的参数是引用的话得使用右值来传递的 ---> 使用 std::ref 来转化一下）
    qDebug() << "_thread_create_pro start" << Qt::endl; // debug
    _thread_create_pro = std::make_shared<ProTreeThread>(std::ref(import_path), std::ref(path),
                                                         _right_btn_item, std::ref(file_count), this, _right_btn_item, nullptr);
    // get 函数获取的是它的原生指针
    connect(_thread_create_pro.get(), &ProTreeThread::SigUpdateProgress, this, &ProTreeWidget::SlotUpdateProgress);
    connect(_thread_create_pro.get(), &ProTreeThread::SigFinishProgress, this, &ProTreeWidget::SlotFinishProgress);

    connect(_dialog_progress, &QProgressDialog::canceled, this, &ProTreeWidget::SlotCancelProgress);
    connect(this, &ProTreeWidget::SigCancelProgress, _thread_create_pro.get(), &ProTreeThread::SlotCancelProgress);

    _thread_create_pro->start();

    _dialog_progress->setWindowTitle("Please wait ...");
    _dialog_progress->setFixedWidth(PROGRESS_WIDTH); // const.h 中的常量
    _dialog_progress->setRange(0, PROGRESS_WIDTH);
    _dialog_progress->exec(); // 做一个模态的进度显示窗口
}
// 设置为活动目录
void ProTreeWidget::SlotSetActive()
{
    if(_right_btn_item == nullptr){
        return ;
    }

    // 先设置字体不加粗
    QFont nullFont;
    nullFont.setBold(false);

    // 判断之前有没有设置过活跃目录
    if(_active_item != nullptr){
        _active_item->setFont(0, nullFont);
    }

    _active_item = _right_btn_item;
    nullFont.setBold(true); // 再设置点击的条目 _right_btn_item 的字体加粗
    _active_item->setFont(0, nullFont);
}
// 点击关闭目录
void ProTreeWidget::SlotClosePro()
{
    // 添加一个删除的对话框 RemoveProDialog
    RemoveProDialog remove_pro_dialog;
    auto res = remove_pro_dialog.exec();
    if(res != QDialog::Accepted){
        return;
    }

    bool b_remove = remove_pro_dialog.IsRemoved();
    auto index_right_item = this->indexOfTopLevelItem(_right_btn_item);
    auto* protreeItem = dynamic_cast<ProTreeItem*>(_right_btn_item); // 获取右键选择"关闭目录"的目录
    auto* selectedItem = dynamic_cast<ProTreeItem*>(_selected_item);
    // auto* selectedItem = dynamic_cast<ProTreeItem*>(_selected_item);
    auto delete_path = protreeItem->GetPath();
    _set_path.remove(delete_path);
    if(b_remove == true){
        QDir delete_dir(delete_path);
        delete_dir.removeRecursively(); // 递归的删除的哦
    }

    // 如果删除的目录和我们当前活跃的目录是同一个，那么设置 _active_item = nullptr
    if(protreeItem == _active_item){
        _active_item = nullptr;
    }

    // 如果关闭的项目正好是双击的项目，那么直接清空
    if(selectedItem && protreeItem == selectedItem->GetRoot()){
        selectedItem = nullptr;
        _selected_item = nullptr;
        emit SigClearSelected();
    }

    // 移除右键选择了"关闭目录"的目录
    delete this->takeTopLevelItem(index_right_item);
    _right_btn_item = nullptr;
}

// 创建项目：关于显示导入进度的槽函数
void ProTreeWidget::SlotUpdateProgress(int file_count)
{
    qDebug() << "file_count is " << file_count << Qt::endl;
    if(_dialog_progress == nullptr){
        qDebug() << "_dialog_progress is empty!!!" << Qt::endl;
        return;
    }

    if(file_count >= PROGRESS_MAX){
        _dialog_progress->setValue(file_count % PROGRESS_MAX);
    }else{
        _dialog_progress->setValue(file_count % PROGRESS_MAX);
    }
}
void ProTreeWidget::SlotFinishProgress()
{
    _dialog_progress->setValue(PROGRESS_MAX);
    _dialog_progress->deleteLater(); // delete
}
void ProTreeWidget::SlotCancelProgress()
{
    // _thread_create_pro->terminate(); // 不推荐的做法
    emit SigCancelProgress();
    delete _dialog_progress;
    _dialog_progress = nullptr; // delete 一个指针之后，赋值为 nullptr/NULL 是一个比较好的做法
}

//// 打开项目
void ProTreeWidget::SlotOpenPro(const QString &open_path)
{
    // 点击打开的项目已经被打开过了，就不用再处理了。直接 return 掉
    if(_set_path.find(open_path) != _set_path.end()){
        return;
    }

    _set_path.insert(open_path);
    QDir pro_dir(open_path); // 把要打开的目录路径做成一个文件目录
    const QString proname = pro_dir.dirName();

    // 模态框实现导入文件的进度展示
    int file_count = 0;
    _open_progressDialog = new QProgressDialog(this);
    qDebug() << "_thread_open_pro is start" << Qt::endl;
    // 也是创建 OpenTreeThread 线程来处理的哦
    // 启动加载导入图片的线程（注意：线程的参数是引用的话得使用右值来传递的 ---> 使用 std::ref 来转化一下）
    _thread_open_pro = std::make_shared<OpenTreeThread>(std::ref(open_path), std::ref(file_count), this, nullptr);

    // get 函数获取的是它的原生指针
    connect(_thread_open_pro.get(), &OpenTreeThread::SigUpdateProgress, this, &ProTreeWidget::SlotUpdateOpenProgress);
    connect(_thread_open_pro.get(), &OpenTreeThread::SigFinishProgress, this, &ProTreeWidget::SlotFinishOpenProgress);

    connect(_open_progressDialog, &QProgressDialog::canceled, this, &ProTreeWidget::SlotCancelOpenProgress);
    connect(this, &ProTreeWidget::SigCancelOpenProgress, _thread_open_pro.get(), &OpenTreeThread::SlotCancelOpenProgress);

    _thread_open_pro->start();

    _open_progressDialog->setWindowTitle("Please wait ...");
    _open_progressDialog->setFixedWidth(PROGRESS_WIDTH); // const.h 中的常量
    _open_progressDialog->setRange(0, PROGRESS_WIDTH);
    _open_progressDialog->exec(); // 做一个模态的进度显示窗口
}

// 打开项目：关于显示导入进度的槽函数
void ProTreeWidget::SlotUpdateOpenProgress(int file_count)
{
    qDebug() << "file_count is " << file_count << Qt::endl;
    if(_open_progressDialog == nullptr){
        qDebug() << "_open_progressDialog is empty!!!" << Qt::endl;
        return;
    }

    if(file_count >= PROGRESS_MAX){
        _open_progressDialog->setValue(file_count % PROGRESS_MAX);
    }else{
        _open_progressDialog->setValue(file_count % PROGRESS_MAX);
    }
}
void ProTreeWidget::SlotFinishOpenProgress()
{
    _open_progressDialog->setValue(PROGRESS_MAX);
    _open_progressDialog->deleteLater(); // delete
}
void ProTreeWidget::SlotCancelOpenProgress()
{
    // _thread_open_pro->terminate(); // 不推荐的做法
    emit SigCancelOpenProgress();
    delete _open_progressDialog;
    _open_progressDialog = nullptr; // delete 一个指针之后，赋值为 nullptr/NULL 是一个比较好的做法
}

// 双击左侧目录树实现图片切换触发的槽函数
void ProTreeWidget::SlotDoubleClickItem(QTreeWidgetItem *doubleItem, int col)
{
    qDebug() << "ProTreeWidget::SlotDoubleClickItem" << Qt::endl;
    if(QGuiApplication::mouseButtons() == Qt::LeftButton)   //判断是否为左键
    {
        auto * tree_doubleItem = dynamic_cast<ProTreeItem*>(doubleItem);
        if(!tree_doubleItem){
            return;
        }
        int itemtype = (int)(tree_doubleItem->type());
        if(itemtype == TreeItemPic){
            emit SigUpdateSelected(tree_doubleItem->GetPath()); // 信号传递了一个 QString 类型的参数
            _selected_item = doubleItem;
        }
    }
}

// 轮播图
void ProTreeWidget::SlotSlideShow()
{
    if(_right_btn_item == nullptr) return;

    // 转化一下变成真实的项目类型 ProTreeItem*
    auto* right_pro_item = dynamic_cast<ProTreeItem*>(_right_btn_item);
    auto* last_child_item = right_pro_item->GetLastPicChild();
    if(last_child_item == nullptr) return;
    auto* first_child_item = right_pro_item->GetFirstPicChild();
    if(first_child_item == nullptr) return;

    // std::shared_ptr 变量，不用 new 来构造的哦
    qDebug() << "first_child_item is " << first_child_item->GetPath();
    qDebug() << "last_child_item is " << last_child_item->GetPath();
    _slide_show_dlg = std::make_shared<SlideShowDlg>(first_child_item, last_child_item, this);
    _slide_show_dlg->setModal(true);
    _slide_show_dlg->showMaximized();
}


// 前进后退按钮切换图片
// _picshow 界面点击了 nextBtn(QPushButton) 后触发的信号，一路传过来的触发的槽函数
void ProTreeWidget::SlotNextClicked(bool ckecked)
{
    if(_selected_item == nullptr){
        return ;
    }

    auto* currentItem = dynamic_cast<ProTreeItem*>(_selected_item)->GetNextItem();
    if(currentItem == nullptr) return;
    emit SigUpdatePic(currentItem->GetPath());
    _selected_item = currentItem;
    this->setCurrentItem(_selected_item);
}
// _picshow 界面点击了 previousBtn(QPushButton) 后触发的信号，一路传过来的触发的槽函数
void ProTreeWidget::SlotPreClicked(bool ckecked)
{
    if(_selected_item == nullptr){
        return ;
    }

    auto* currentItem = dynamic_cast<ProTreeItem*>(_selected_item)->GetPreItem();
    if(currentItem == nullptr) return;
    emit SigUpdatePic(currentItem->GetPath());
    _selected_item = currentItem;
    this->setCurrentItem(_selected_item);
}

// 设置音乐
void ProTreeWidget::SlotSetMusic(bool)
{
    qDebug() << "SlotSetMusic" << Qt::endl;
    QFileDialog file_dialog;
    file_dialog.setFileMode(QFileDialog::ExistingFiles);
    file_dialog.setWindowTitle("选择导入的文件夹");
    file_dialog.setDirectory(QDir::currentPath());
    file_dialog.setViewMode(QFileDialog::Detail);
    file_dialog.setNameFilter("(*.mp3)");
    QStringList fileNames;
    if (file_dialog.exec()){
        fileNames = file_dialog.selectedFiles();
    }
    if(fileNames.length() <= 0){
        return;
    }
    _playlist->clear();
    for(auto filename : fileNames){
        qDebug() << "filename is " << filename << Qt::endl;
        _playlist->addMedia(QUrl::fromLocalFile(filename));
    }
    if(_player->state() != QMediaPlayer::PlayingState)
    {
        _playlist->setCurrentIndex(0);
    }
}
void ProTreeWidget::SlotStartMusic()
{
    qDebug()<< "ProTreeWidget::SlotStartMusic" << Qt::endl;
    _player->play();
}
void ProTreeWidget::SlotStopMusic()
{
    qDebug()<< "ProTreeWidget::SlotStopMusic" << Qt::endl;
    _player->pause();
}

